-
-
Notifications
You must be signed in to change notification settings - Fork 277
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Infer the type of the result of calling typing.cast() #1076
Infer the type of the result of calling typing.cast() #1076
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for the pull request ! It's pretty straightforward :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure we should infer b
as instance of A
for b = cast(A, x)
. cast
is used just for type hints and we probably shouldn't mix astroid inference and type hints. IMO the logical step would be to infer b
as x
since that's what cast
does. @Pierre-Sassoulas What do you think?
Thanks for the helpful review comments. In terms of what the inferred type of the result should be, maybe I'm fixing this in the wrong place. The original motivation was this report in Pylint; if we infer that The way I look at it, |
@timmartin I'm a bit hesitant with this one. Who makes sure
One last thing, it's should be possible to use abstract classes for |
The developer who adds the cast is responsible for checking that To me, the issue is that I think you're right in theory that any problem that can be solved by a cast can be solved by sufficiently good type declarations / better inference. I think casting exists for the cases where that doesn't yet exist. |
The issue I have with it is that It might be an idea to add something like |
It would add work for pylint users, what is the meaningful difference between typing for inference and typing for type/mypy ? I think |
@Pierre-Sassoulas The point I'm trying to make here is that with inference we can already do better then what type checkers can. So using |
Well it's true that it might prevent us from offering better suggestions but only when the user made an explicit typing mistake. I think it add something for us if the inference fail. So maybe we should rely on |
AIUI type checkers like mypy already do type inference, they can't rely on every variable having its type statically declared. Is there a class of inference that Astroid does that wouldn't be available in a sufficiently smart type checker? I can certainly see how there will be cases in the real world where the cast may be needed for mypy and not for Pylint, say. That would make it annoying if adding the needed cast helped mypy but broke Pylint. On the other hand, there will be cases where Astroid isn't (yet) making the inference and it would be useful to have the option of a cast. It should be easy enough to make it infer the type of TBH I don't have a strong opinion here, I just picked this one up because I thought it would be an easy way to get used to the codebase. If it's controversial, I'm happy to leave this to someone else. |
@hippo91 do you have an opinion on this ? |
Well that is not an easy question. Thanks all for giving your point of view. IMHO the best option here is to infer the result of the cast as 'A' only if the inference of 'x' failed. Otherwise I am afraid we lose precious informations as @cdce8p mentioned it. But I am afraid there is not a real clear solution for this. |
Thanks for your input @hippo91! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good overall! Just a few last comments
4045b6e
to
1d4a2a0
Compare
@Pierre-Sassoulas I would like to include it in |
cf8c4c8
to
e791ed1
Compare
@timmartin Either that or raising |
I think my latest change deals with both cases. I'm not totally sure in the typevar case; in my testing it appears that the typevar just gets inferred to |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Astroid does have some (albeit limited) inference for TypeVar
(see below). The issue for us here is that it basically returns an empty class with the bare minimum and doesn't account for and constraints or bounds on the original TypeVar.
Just from a quick view, I fear we won't be able to easily find out if a type is a TypeVar
or not. That unfortunately will bring us back to the point I made at the beginning: It's probably best to only infer cast
as the variable itself even if it's Uninferable
.
If you have another idea, I would be open to testing that out.
ChangeLog
Outdated
@@ -21,6 +20,8 @@ Release date: TBA | |||
|
|||
Closes PyCQA/pylint#4671 | |||
|
|||
* Added support to infer return type of typing.cast() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
* Added support to infer return type of typing.cast() | |
* Added support to infer return type of ``typing.cast()`` |
The ChangeLog ist rst
formatted.
tests/unittest_brain.py
Outdated
"""Casting to a typevar is not currently inferred""" | ||
node = builder.extract_node( | ||
""" | ||
from typing import cast |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
from typing import cast | |
from typing import cast, TypeVar |
That's a shame. I'm a little puzzled though, because I was assuming that astroid would either successfully determine that the argument was a TypeVar, or else it would be uninferable. Are you saying that TypeVars are handled in a way that makes it impossible to distinguish a class from a typevar? |
At the moment that is the case. Keep in mind though that this behavior is completely fine since |
If that's the case then it's probably best to do as you suggest and just infer from the second argument. Will astroid differentiate between classes and typevars in the future? It seems like it would be necessary to catch some errors e.g. that typevars can't be constructed. Looking at the typevar code, is there any way to distinguish based on metaclass? It looks like typevars are given a custom metaclass; if we could only infer |
I would probably prefer that.
Maybe, there are multiple issues though. First you need someone to add it, then to review it, and most important someone to maintain it. (1) might be possible, but the other two unlikely. As it currently is, I too struggle sometimes to understand a change completely. That's the cost of good, but really old legacy code. Regarding
You could try I know, that's probably not the answer you were hoping for but that's how I feel about it. I hope you can understand it. |
4bd6ebe
to
9e51d37
Compare
I think my last change does what's required here. Should I change the tags on this PR to indicate that it's ready for re-review? |
@timmartin there's a little "reload" button in the reviewers so you can ask for a new review that way. :) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the ping. I must have missed your last push.
As for the PR, I committed some last changes (I've explained the reasoning behind them below).
It looks good now.
Thank you @timmartin 🐬
if not isinstance(node.func, (Name, Attribute)): | ||
raise UseInferenceDefault |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Technically this is covered by _looks_like_typing_cast
but type checker don't know about that.
assert isinstance(inferred, nodes.Const) | ||
assert inferred.value == 42 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Usually it's a bit easier to test for a const value.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍 Thank you for being so persistent 👏 This will go in astroid 2.6.6 then pylint 2.10
Description
Added an inference rule in
brain_typing.py
to infer the return type oftyping.cast
. So that:Type of Changes